package com.simpou.commons.model;

import com.simpou.commons.model.behavior.Identifiable;
import com.simpou.commons.model.exception.IllegalIdentityException;
import com.simpou.commons.utils.reflection.Casts;
import java.io.Serializable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

/**
 * Objeto a ser delegado a um objeto identificável.
 *
 * @author Jonas Pereira
 * @since 2013-06-30
 * @version 2013-06-30
 */
@RequiredArgsConstructor
public class IdentifiableModelDelegate<T extends Serializable>{

    @Setter
    @Getter
    private T id;

    private final Class<T> clasz;

    public IdentifiableModelDelegate() {
        this(null);
    }

    public T identity() {
        return getId();
    }

    public void checkedId(T id) {
        setId(id);
    }

    public void uncheckedId(Serializable id) {
        if (id == null) {
            setId(null);
        } else if (clasz.isAssignableFrom(id.getClass())) {
            setId(Casts.objCast(clasz, id));
        } else {
            throw new IllegalIdentityException(clasz, id.getClass());
        }
    }

    @Override
    public final int hashCode() {
        int hash = 7;
        hash = 79 * hash + (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }

    
    public final boolean equals(Identifiable obj1, Object obj2) {
        if (obj2 == null) {
            return false;
        }

        if (obj1.getClass() != obj2.getClass()) {
            return false;
        }

        final Identifiable<?> identObj = (Identifiable<?>) obj2;
        final T thisId = this.identity();
        if (identObj.identity() == null) {
            return thisId == null;
        }

        if (identObj.identity().getClass() != clasz) {
            return false;
        }

        final T otherId = (T) identObj.identity();

        return otherId.equals(thisId);
    }
}
